package com.btm.mcp.business.service;

import com.btm.mcp.business.model.BusinessTerm;
import com.btm.common.model.PageResult;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.meilisearch.sdk.Client;
import com.meilisearch.sdk.Index;
import com.meilisearch.sdk.SearchRequest;
import com.meilisearch.sdk.exceptions.MeilisearchException;
import com.meilisearch.sdk.model.DocumentsQuery;
import com.meilisearch.sdk.model.Results;
import com.meilisearch.sdk.model.Searchable;
import jakarta.annotation.PostConstruct;
import lombok.Getter;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class BusinessTermService {

    private final Client meiliSearchClient;
    private final ObjectMapper objectMapper = new ObjectMapper();
    private static final String INDEX_NAME = "business_terms";
    @Getter
    private Index index;

    public BusinessTermService(Client meiliSearchClient) {
        this.meiliSearchClient = meiliSearchClient;
    }

    @PostConstruct
    public void init() {
        try {
            this.index = meiliSearchClient.index(INDEX_NAME);
            // Check if the index exists. If not, Meilisearch will create it on the first document addition.
            // but we can create it explicitly if we want to set settings beforehand.
            try {
                meiliSearchClient.getIndex(INDEX_NAME);
            } catch (MeilisearchException e) {
                if (e.getMessage().equals("Index `"+INDEX_NAME+"` not found.")) {
                    meiliSearchClient.createIndex(INDEX_NAME, "id");
                } else {
                    throw e;
                }
            }
            this.index = meiliSearchClient.index(INDEX_NAME);
        } catch (MeilisearchException e) {
            // Handle exceptions, e.g., connection error
            throw new RuntimeException("Failed to initialize MeiliSearch index", e);
        }
    }

    public PageResult<BusinessTerm> getAllTerms(int page, int size) throws MeilisearchException {
        DocumentsQuery query = new DocumentsQuery();
        query.setOffset(page * size);
        query.setLimit(size + 1); // 多查一条判断是否有下一页
        Results<BusinessTerm> result = index.getDocuments(query, BusinessTerm.class);
        List<BusinessTerm> all = Arrays.asList(result.getResults());
        boolean hasNext = all.size() > size;
        List<BusinessTerm> data = hasNext ? all.subList(0, size) : all;
        return new PageResult<>(data, hasNext);
    }

    public BusinessTerm addTerm(BusinessTerm term) throws MeilisearchException {
        if (term.getId() == null || term.getId().isEmpty()) {
            term.setId(UUID.randomUUID().toString());
        }
        String document = objectMapper.valueToTree(term).toString();
        index.addDocuments(String.format("[%s]", document));
        return term;
    }

    public BusinessTerm updateTerm(BusinessTerm term) throws MeilisearchException {
        try {
            String document = objectMapper.valueToTree(term).toString();
            index.updateDocuments(String.format("[%s]", document));
            return term;
        } catch (Exception e) {
            throw new MeilisearchException();
        }
    }

    public void deleteTerm(String id) throws MeilisearchException {
        index.deleteDocument(id);
    }

    public PageResult<BusinessTerm> searchTerms(String keyword, int page, int size) throws MeilisearchException {
        SearchRequest searchRequest = new SearchRequest(keyword)
                .setOffset(page * size)
                .setLimit(size + 1);
        Searchable searchResult = index.search(searchRequest);
        ArrayList<HashMap<String, Object>> hits = searchResult.getHits();
        List<BusinessTerm> termList = new ArrayList<>(hits.size());
        for (HashMap<String, Object> hit : hits) {
            termList.add(new BusinessTerm((String) hit.get("id"), (String) hit.get("name"), (String) hit.get("description")));
        }
        boolean hasNext = termList.size() > size;
        List<BusinessTerm> data = hasNext ? termList.subList(0, size) : termList;
        return new PageResult<>(data, hasNext);
    }
} 